/*
        Copyright 2018 Gaurav Kumar

        Licensed under the Apache License, Version 2.0 (the "License");
        you may not use this file except in compliance with the License.
        You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

        Unless required by applicable law or agreed to in writing, software
        distributed under the License is distributed on an "AS IS" BASIS,
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        See the License for the specific language governing permissions and
        limitations under the License.
*/

package com.gauravk.audiovisualizer.base;

import com.gauravk.audiovisualizer.model.AnimSpeed;
import com.gauravk.audiovisualizer.model.PaintStyle;
import com.gauravk.audiovisualizer.model.PositionGravity;
import com.gauravk.audiovisualizer.utils.AVConstants;

import ohos.agp.components.AttrSet;
import ohos.agp.components.ComponentContainer;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.media.audio.AudioWaver;


/**
 * Base class for the visualizers
 * <p>
 * Created by gk
 */

public abstract class BaseVisualizer extends ComponentContainer {
    protected byte[] mRawAudioBytes;
    protected Paint mPaint;
    protected Color mColor = AVConstants.DEFAULT_COLOR;
    protected byte[] bytes;

    protected PaintStyle mPaintStyle = PaintStyle.FILL;
    protected PositionGravity mPositionGravity = PositionGravity.BOTTOM;

    protected float mStrokeWidth = AVConstants.DEFAULT_STROKE_WIDTH;
    protected float mDensity = AVConstants.DEFAULT_DENSITY;

    protected AnimSpeed mAnimSpeed = AnimSpeed.MEDIUM;
    protected boolean isVisualizationEnabled = true;

    private AudioWaver mAudioWaver;

    /**
     * 使用java代码实例化调用
     *
     * @param context
     */
    public BaseVisualizer(Context context) {
        super(context);
        init(context, null);
        init();
    }

    /**
     * 使用xml布局引用调用
     *
     * @param context
     * @param attrSet
     */
    public BaseVisualizer(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context, attrSet);
        init();
    }

    /**
     * 使用xml并设置style调用
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public BaseVisualizer(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context, attrSet);
        init();
    }

    /**
     * 子类初始化操作
     */
    protected abstract void init();

    private void init(Context context, AttrSet attrs) {
        this.mDensity = attrs.getAttr("avDensity").get().getFloatValue();
        this.mColor = attrs.getAttr("avColor").get().getColorValue();
        this.mStrokeWidth = attrs.getAttr("avWidth").get().getDimensionValue();
        String avType = attrs.getAttr("avType").get().getStringValue();
        if (avType != null && !avType.equals("")) {
            this.mPaintStyle = avType.toLowerCase().equals("outline") ? PaintStyle.OUTLINE : PaintStyle.FILL;
        }
        String avSpeed = attrs.getAttr("avSpeed").get().getStringValue();
        if (avSpeed != null && !avSpeed.equals("")) {
            this.mAnimSpeed = AnimSpeed.MEDIUM;
            if (avSpeed.toLowerCase().equals("slow")) {
                this.mAnimSpeed = AnimSpeed.SLOW;
            }
            else if (avSpeed.toLowerCase().equals("fast")) {
                this.mAnimSpeed = AnimSpeed.FAST;
            }
        }

        mPaint = new Paint();
        mPaint.setColor(mColor);
        mPaint.setStrokeWidth(mStrokeWidth);
        if (mPaintStyle == PaintStyle.FILL) {
            mPaint.setStyle(Paint.Style.FILL_STYLE);
        }
        else {
            mPaint.setStyle(Paint.Style.STROKE_STYLE);
        }
    }

    /**
     * Set color to visualizer with color resource id.
     *
     * @param color color resource id.
     */
    public void setColor(Color color) {
        this.mColor = color;
        this.mPaint.setColor(this.mColor);
    }

    /**
     * Set the density of the visualizer
     *
     * @param density density for visualization
     */
    public void setDensity(float density) {
        synchronized (this) {
            this.mDensity = density;
            init();
        }
    }

    /**
     * Sets the paint style of the visualizer
     *
     * @param paintStyle style of the visualizer.
     */
    public void setPaintStyle(PaintStyle paintStyle) {
        this.mPaintStyle = paintStyle;
        this.mPaint.setStyle(paintStyle == PaintStyle.FILL ? Paint.Style.FILL_STYLE : Paint.Style.STROKE_STYLE);
    }

    /**
     * Sets the position of the Visualization{@link PositionGravity}
     *
     * @param positionGravity position of the Visualization
     */
    public void setPositionGravity(PositionGravity positionGravity) {
        this.mPositionGravity = positionGravity;
    }

    /**
     * Sets the Animation speed of the visualization{@link AnimSpeed}
     *
     * @param animSpeed speed of the animation
     */
    public void setAnimationSpeed(AnimSpeed animSpeed) {
        this.mAnimSpeed = animSpeed;
    }

    /**
     * Sets the width of the outline {@link PaintStyle}
     *
     * @param width style of the visualizer.
     */
    public void setStrokeWidth(float width) {
        this.mStrokeWidth = width;
        this.mPaint.setStrokeWidth(width);
    }

    /**
     * Sets the audio session id for the currently playing audio
     *
     * @param audioSessionId of the media to be visualised
     */
    public void setAudioSessionId(int audioSessionId) {
        mAudioWaver = new AudioWaver(audioSessionId, this.getClass().getName());
        mAudioWaver.setActivated(false);
        mAudioWaver.setDataSize(AudioWaver.getMaxDataSize());
        mAudioWaver.setWaveDataObserver(new AudioWaver.WaveDataObserver() {
            @Override
            public void onWaveData(byte[] mBytes, int i) {
                BaseVisualizer.this.mRawAudioBytes = mBytes;
                // 刷新
                getContext().getUITaskDispatcher().syncDispatch(new Runnable() {
                    @Override
                    public void run() {
                        invalidate();
                    }
                });
            }
        }, AudioWaver.getMinInterval());
        mAudioWaver.setActivated(true);
    }
}